using UnityEngine;
using System.Collections;



/*	IDÉE:
	- il reste une bande bleue sur les côtés -> c'est l'overlap
	- je fais une taille arbitraire pour la largeur de mes tuiles et adapte la caméra afin que ça fit pile..
		..dans l'écran. Les scores etc.. sont définis par rapport au bord de l'écran. S'il est petit, ils..
		.. empièteront sur les tuiles. S'il est grand, j'aurai des barres bleues en haut et bas. Pas grave.
		=> Est-ce que j'étire les tuiles pour éviter les barres bleues sur smartphone?
		=> Est-ce que j'envisage un cas où l'écran serait assez large pour les tuiles mais pas assez haut?
			

Améliorations:
	- ?? rajouter un petit délai entre deux jokers ??
	- Etirer les tiules lorsqu'on joue sur smartphone et aussi une tablette d'ailleurs
	
BUGS:
	
*/

public class MatchChecker : MonoBehaviour {
	public TileSelection selectedTile;
	public TileSelection[] jokerTiles = new TileSelection[2];
	
//"Voir si je peux mettre des #MOBILE/ORDI pour le compilateur plutôt que tout commenter
	public bool[][] _jokerMatrix;		//Copy of the game active tiles matrix; used by jokerFind to find the next joker
	private TilesGenerator _gen;
	private GUIScript _gui;
	

	// Use this for initialization
	public void Initialize ()
	{
	
		selectedTile = null;
		jokerTiles[0] = null;
		jokerTiles[1] = null;
		
		
		_gen = this.GetComponent<TilesGenerator>();
		_gui = this.GetComponent<GUIScript>();
		
		_jokerMatrix = new bool[_gen.height+2][];
		for( int i = 0; i < _gen.height+2; i++)
			_jokerMatrix[i] = new bool[_gen.width+2];
	}


	/// <summary>
	/// Registers the newly selected tile and launches a match check if need be.
	/// </summary>
	/// <param name="newTile">The tile which just got clicked</param>
	public void TileSected(TileSelection newTile)
	{
		// NewTile cannot be null since the tiles call this method with 'this' as parameter 

		// If this tile was already selected -> do nothing
		if( selectedTile == newTile )
			return;

		//If no tile selected -> add the new one
		if( null == selectedTile )
		{
			selectedTile = newTile;
			SoundEffectsHelper.Instance.MakeSelectionSound();
			return;
		}

		//If a non-compatible tile was selected -> unselect the previous tile and add the new one to 0
		if(selectedTile.name[0] != newTile.name[0])
		{
			selectedTile.Unselect();
			selectedTile = newTile;
			SoundEffectsHelper.Instance.MakeSelectionSound();
			return;
		}

		// If another compatible tile was already selected -> launch a check
		if( ConfrontTiles(selectedTile,newTile) )
		{
			SoundEffectsHelper.Instance.MakeVanishSound();
			_gui.currentScore += 10;
			_gen.NumberOfTiles -= 2;
			if( _gen.NumberOfTiles <= 0 )
				_gui.NoTilesLeft();
		}		
	}
	
	
	/// <summary>
	/// Confronts the tiles A & B to see if they form a valid pair. If yes, removes them.
	/// If not, A will be unselected and B will be the selected tile.
	/// </summary>
	/// <param name="_A">First Tile of the pair.</param>
	/// <param name="_B">Second Tile of the pair.</param>
	/// <returns>True if tiles were removed. False otherwise. </returns>
	public bool ConfrontTiles(TileSelection _A, TileSelection _B)
	{
		if( CheckMatch(_A,_B) )
		{
			//If the pair can be connected, we remove the tiles
			// We use _A instead of selectedTile because this method is also called ..
			// .. to check on Joker pairs.
			_A.Deactivate();
			_B.Deactivate();
			
			//If one of the tiles was part of the Joker pair, we find a new joker
			if( _A == jokerTiles[0] || _B == jokerTiles[0] || _A == jokerTiles[1] || _B == jokerTiles[1] )
				JokerFinder();
			
			_A = _B = selectedTile = null;
			return true;
		}
		else
		{
			//If the pair cannot be connected, we only keep the 2d one as selected
			selectedTile.Unselect();
			selectedTile = _B;
			return false;
		}
	}
	
	/// <summary>
	/// Removes the joker tiles and prepares the next ones.
	/// </summary>
	/// <returns><c>true</c>, If next joker is ready <c>false</c> If no tiles left or no joker found.</returns>
	public bool UseJoker()
	{
		jokerTiles[0].DeactivateWithAnimation();		
		jokerTiles[0] = null;
		jokerTiles[1].DeactivateWithAnimation();
		jokerTiles[1] = null;
		
		
		_gen.NumberOfTiles -= 2;
		_gui.currentJoker -= 1;
		if( _gen.NumberOfTiles > 0 )
			return JokerFinder();
		else
			return false;
	}


	/// <summary>
	/// Pathfinder for the two selected tiles. Returns true if they can be connected.
	/// </summary>
	bool CheckMatch(TileSelection _A, TileSelection _B)
	{
		int i1 = _A.i;
		int j1 = _A.j;
		int i2 = _B.i;
		int j2 = _B.j;
		
		//First we deal with the trivial cases where the tiles touch each other
		if( 1 == Mathf.Abs(i1-i2) + Mathf.Abs(j1-j2) )
			return true;
		
		//Horizontal bar
		//We check the tiles above the selected one and then below for free spaces
		for(int i = i1-1; i >= 0; i--)
		{
			int x = TestPath_h(i,i2,j1,j2);
			//If a path was found, we return true
			if( 1 == x )
				return true;
			//If a tile blocks the way, we break
			else if( -1 == x )
				break;
		}

		// We do the same with the tiles below the selected one
		for(int i = i1+1; i < _gen.height +2; i++)
		{
			int x = TestPath_h(i,i2,j1,j2);
			//If a path was found, we return true
			if( 1 == x )
				return true;
			//If a tile blocks the way, we break
			else if( -1 == x )
				break;
		}
		
		
		//Vertical bar
		for(int j = j1-1; j >= 0; j--)
		{
			int x = TestPath_v(i1,i2,j,j2);
			//If a path was found, we return true
			if( 1 == x )
				return true;
			//If a tile blocks the way, we break
			else if( -1 == x )
				break;
		}

		// We do the same with the tiles below the selected one
		for(int j = j1+1; j < _gen.width +2; j++)
		{
			int x = TestPath_v(i1,i2,j,j2);
			//If a path was found, we return true
			if( 1 == x )
				return true;
			//If a tile blocks the way, we break
			else if( -1 == x )
				break;
		}

		return false;

	}
	
	/// <summary>
	/// Tries to reach i2,j2 starting from tile i,j1.
	/// </summary>
	/// <returns>1 if it succeeds, 0 if it fails, -1 if the path is blocked</returns>
	int TestPath_h(int i, int i2, int j1, int j2)
	{
		//If the tile is there, it blocks the way -> we break (with the exception of the selected tile itself)
		if( true == _gen.Tiles[i][j1].isVisible )
			return -1;
		// We check if the bar is clear between the columns j1 & j2 on the row i
		if( OpenBar_h(i,j1,j2) )
			//If yes, then we check the tile which we have reached: it should be either our goal, either empty
			// then we see if a V bar can connect to tile 2
			if( i == i2 )
				return 1;
			else if( false == _gen.Tiles[i][j2].isVisible && OpenBar_v(i,i2,j2) )
				//If it's ok then we return true: it is a match
				return 1;

		return 0;
	}


	/// <summary>
	/// Tries to reach i2,j2 starting from tile i,j1.
	/// </summary>
	/// <returns>1 if it succeeds, 0 if it fails, -1 if the path is blocked</returns>
	int TestPath_v(int i1, int i2, int j, int j2)
	{
		//If the tile is there, it blocks the way -> we break (with the exception of the selected tile itself)
		if( true == _gen.Tiles[i1][j].isVisible )
			return -1;
		// We check if the bar is clear between the rows i1 & i2 on the column j
		if( OpenBar_v(i1,i2,j) )
			//If yes, then we check the tile which we have reached: it should be either our goal, either empty
			// then we see if a V bar can connect to tile 2
			if( j == j2 )
				return 1;
			else if( false == _gen.Tiles[i2][j].isVisible && OpenBar_h(i2,j,j2) )
				//If it's ok then we return true: it is a match
				return 1;
		
		return 0;
	}

	private bool OpenBar_h(int i, int _a, int _b)
	{
		int a,b;
		a = Mathf.Min(_a,_b);
		b = Mathf.Max(_a,_b);

		for(int n = a+1; n < b; n++ )
			if( true == _gen.Tiles[i][n].isVisible )
				return false;	//If a tile stands in the was, we're blocked -> False
		//The whole H line is free
		return true;
	}
	
	private bool OpenBar_v(int _a, int _b, int j)
	{
		int a,b;
		a = Mathf.Min(_a,_b);
		b = Mathf.Max(_a,_b);
		
		for(int n = a+1; n < b; n++ )
			if( true == _gen.Tiles[n][j].isVisible )
				return false;	//If a tile stands in the was, we're blocked -> False
		
		//The whole V line is free
		return true;
	}

	// Update is called once per frame
	void Update () {
	
	}
	
	/// <summary>
	/// We parse the matrix in a snail-like shape: for each tile we locate the possible pairs..
	/// .. and test if they are accessible.
	/// </summary>
	/// <returns><c>true</c>, if a joker was found, <c>false</c> otherwise.</returns>
	public bool JokerFinder()
	{
		int i1 = 1;
		int i2 = _gen.height;
		int j1 = 1;
		int j2 = _gen.width;
		
		// We begin by filling the matrix which will be used to know which tiles have already..
		// ..been tested
		for( int i = 1; i < _gen.height+1; i++ )
			for( int j = 1; j < _gen.width+1; j++ )
				_jokerMatrix[i][j] = _gen.Tiles[i][j].isVisible;

		
		while(i1<=i2 && j1 <= j2)
		{
			for( int j = j1; j <= j2; j++)
				if( _jokerMatrix[i1][j] )		//We check if the tile should be tested
					if( SubSnail(i1,j) )
						return true;
				//else

			i1++;
			for( int i = i1; i <= i2; i++)
				if( _jokerMatrix[i][j2] )		//We check if the tile should be tested
					if( SubSnail(i,j2) )
						return true;
			j2--;
			for( int j = j2; j >= j1; j--)
				if( _jokerMatrix[i2][j] )		//We check if the tile should be tested
					if( SubSnail(i2,j) )
						return true;

			i2--;
			for( int i = i2; i >= i1; i--)
				if( _jokerMatrix[i][j1] )		//We check if the tile should be tested
					if( SubSnail(i,j1) )
						return true;

			j1++;			
		}
		//Nothing was found: there is no valid pair left
		return false;
	}
	
	/// <summary>
	///	Parses the remaining part of the snail looking for a matching tile to x,
	/// checks if the path exists; if not, searches for the next match and so on.
	/// </summary>
	/// <param name="_i,_j">The coordinates of the first tile</param>
	bool SubSnail(int _ia, int _ja)
	{
		int n;
		
		_jokerMatrix[_ia][_ja] = false;

		// We register how many matching tiles may exist
		n = _gen.Tiles[_ia][_ja].matchingTiles;

		for( int i = 1; i <= _gen.height; i++ )
			for( int j = 1; j <= _gen.width; j++ )
				if( _gen.Tiles[i][j].isVisible && (i != _ia || j != _ja)
					&& _gen.Tiles[i][j].name[0] == _gen.Tiles[_ia][_ja].name[0] )
				{
					if( CheckMatch(_gen.Tiles[_ia][_ja],_gen.Tiles[i][j]) )
					{
						jokerTiles[0] = _gen.Tiles[_ia][_ja];
						jokerTiles[1] = _gen.Tiles[i][j];
						return true;					
					}
					else
					{
						n--;
						if( 0 >= n )
						{
							//If the tested tile was a simple pair, then the 2nd one can be removed..
							// .. from the list of the tiles to be tested too.
							if( 1 == _gen.Tiles[i][j].matchingTiles )
								_jokerMatrix[i][j] = false;
							return false;
						}
					}
				}
		return false;	//should never be reached
	}
}
